import base64
import pickle

from django.shortcuts import render
from django_redis import get_redis_connection
from rest_framework.response import Response
from rest_framework.views import APIView


# Create your views here.
from carts.serializers import CartSerializers, SKUSerializer, CartDeleteSerializers, CartSelectedSerializers
from goods.models import SKU


class CartsView(APIView):

    def perform_authentication(self, request):
        #在调用post方法之前不让程序进行验证是否登陆操作
        pass

    def post(self,request):
        '''
            保存购物车数据
        :param request:
        :return:
        '''
        #获取前端数据
        data = request.data
        #验证数据
        serializer = CartSerializers(data=data)
        serializer.is_valid(raise_exception=True)

        #验证后的结果
        sku_id = serializer.validated_data['sku_id']
        count = serializer.validated_data['count']
        selected = serializer.validated_data['selected']

        #判断用户是否登陆
        try:
            user = request.user
        except:
            user = None

        if user is not None:
            #表示用户已登录
            #建立缓存连接
            conn = get_redis_connection('cart')
            # 保存hash类型和集合类型    hincrby()进行累加写入数据
            conn.hincrby('cart_%s'%user.id, sku_id, count)
            if selected:
                conn.sadd('cart_selected_%s'%user.id, sku_id)
            # 返回结果
            return Response('ok')
        else:
            #用户未登录
            # 先判断是否有Cookie数据
            cart_cookie = request.COOKIES.get('cart_cookie')
            if cart_cookie:
                # 解密
                cart = pickle.loads(base64.b64decode(cart_cookie))
            else:
                # 如果没有cookie,先定义一个空字典
                cart = {}

            # 有cookie则获取cookie值累加
            sku_dict = cart.get(sku_id)
            if sku_dict:
                count += int(sku_dict['count'])

            cart[sku_id]={
                'count':count,
                'selected':selected,
            }

            # 将新的字典数据写入cookie
            response = Response('ok')
            cart_cookie = base64.b64encode(pickle.dumps(cart)).decode()
            response.set_cookie('cart_cookie',cart_cookie,max_age=60*60*24)
            # 返回结果
            return response

    def get(self,request):
        '''
            获取购物车数据
        :param request:
        :return:
        '''
        #判断用户是否登陆
        try:
            user = request.user
        except:
            user = None

        if user is not None and user.is_authenticated:
            #表示用户已登录
            #建立缓存连接
            conn = get_redis_connection('cart')
            # 获取hash类型和集合类型
            sku_id_count = conn.hgetall('cart_%s'%user.id)
            sku_selected = conn.smembers('cart_selected_%s'%user.id)
            cart = {}
            for sku_id,count in sku_id_count.items():
                cart[int(sku_id)] = {
                    'count':int(count),
                    'selected':sku_id in sku_selected,
                }

        else:
            #用户未登录
            # 先判断是否有Cookie数据
            cart_cookie = request.COOKIES.get('cart_cookie')
            if cart_cookie:
                # 解密
                cart = pickle.loads(base64.b64decode(cart_cookie.encode()))

            else:
                # 如果没有cookie,先定义一个空字典
                cart = {}


        # 获取商品对象
        skus = SKU.objects.filter(id__in=cart.keys())
        for sku in skus:
            sku.count = cart[sku.id]['count']
            sku.selected = cart[sku.id]['selected']
        serializer = SKUSerializer(skus, many=True)

        return Response(serializer.data)

    def put(self,request):
        '''
            修改购物车数据
        :param request:
        :return:
        '''
        # 获取前端数据并进行验证
        serializer = CartSerializers(data=request.data)
        serializer.is_valid(raise_exception=True)

        # 获取验证后的数据结果
        sku_id = serializer.validated_data.get('sku_id')
        count = serializer.validated_data.get('count')
        selected = serializer.validated_data.get('selected')

        # 验证用户是否登陆
        try:
            user = request.user
        except Exception:
            #验证失败,用户未登录
            user = None

        if user is not None and user.is_authenticated:
            # 用户已登录,在redis中保存
            # 连接redis 创建链接对象
            redis_conn = get_redis_connection('cart')
            # 使用管道
            pl = redis_conn.pipeline()
            # 覆盖原有数据
            pl.hset('cart_%s'%user.id,sku_id,count)
            #判断选中状态
            if selected:
                pl.sadd('cart_selected_%s'%user.id,sku_id)
            else:
                # false则将集合中sku_id删除掉
                pl.srem('cart_selected_%s'%user.id,sku_id)

            pl.execute()

            return Response(serializer.data)
        else:
            # 用户未登录,在cookie中保存  使用pickle序列化购物车数据,pickle操作的是bytes类型

            # 先判断是否有cookie存在
            cart_cookie = request.COOKIES.get('cart')
            if cart_cookie is not None:
                cart = pickle.loads(base64.b64decode(cart_cookie.encode()))
            else:
                cart = {}
            # 将数据更新到字典中
            cart[sku_id] = {
                'count':count,
                'selected':selected,
            }
            #加密
            cookie_cart = base64.b64encode(pickle.dumps(cart)).decode()

            response = Response(serializer.data)
            #设置购物车的cookie  需要设置有效期否则为临时cookie
            response.set_cookie('cart',cookie_cart,max_age=60*60*7)
            return response

    def delete(self,request):
        '''
            删除数据
        :param request:
        :return:
        '''
        # 获取前端数据  sku_id
        data = request.data
        # 验证数据
        serializer = CartDeleteSerializers(data=data)
        serializer.is_valid(raise_exception=True)

        # 验证后的结果
        sku_id = serializer.validated_data['sku_id']

        # 判断用户是否登陆
        try:
            user = request.user
        except:
            user = None

        if user is not None:
            # 表示用户已登录
            # 建立缓存连接
            conn = get_redis_connection('cart')
            # 删除hash类型和集合类型
            conn.hdel('cart_%s' % user.id, sku_id)
            conn.srem('cart_selected_%s' % user.id, sku_id)
            # 返回结果
            return Response('ok')
        else:
            # 用户未登录
            # 生成响应对象
            response = Response('ok')

            # 先判断是否有Cookie数据
            cart_cookie = request.COOKIES.get('cart_cookie')
            if cart_cookie:
                # 解密
                cart = pickle.loads(base64.b64decode(cart_cookie))
                # 删除cookie中的数据
                if sku_id in cart:
                    del cart[sku_id]

                cart_cookie = base64.b64encode(pickle.dumps(cart)).decode()
                response.set_cookie('cart_cookie', cart_cookie, max_age=60 * 60 * 24)
            # 返回结果
            return response


class CartSelectionView(APIView):

    def perform_authentication(self, request):
        #在调用post方法之前不让程序进行验证是否登陆操作
        pass

    def put(self,request):
        '''
            购物车全选操作
        :param request:
        :return:
        '''
        # 获取前端数据并进行验证
        serializer = CartSelectedSerializers(data=request.data)
        serializer.is_valid(raise_exception=True)

        # 获取验证后的数据结果
        selected = serializer.validated_data.get('selected')

        # 验证用户是否登陆
        try:
            user = request.user
        except Exception:
            #验证失败,用户未登录
            user = None

        if user is not None and user.is_authenticated:
            # 用户已登录,在redis中保存
            # 连接redis 创建链接对象
            redis_conn = get_redis_connection('cart')

            # 获取所有的sku_id值
            sku_id_count = redis_conn.hgetall('cart_%s'%user.id)  #{ 15:1,16:1 }
            sku_ids = sku_id_count.keys()
            #更新选中状态
            if selected:
                redis_conn.sadd('cart_selected_%s'%user.id,*sku_ids)
            else:
                # false则将集合中sku_id删除掉
                redis_conn.srem('cart_selected_%s'%user.id,*sku_ids)

            return Response(serializer.data)
        else:
            # 用户未登录,在cookie中保存  使用pickle序列化购物车数据,pickle操作的是bytes类型

            response = Response(serializer.data)

            # 先判断是否有cookie存在
            cart_cookie = request.COOKIES.get('cart')
            if cart_cookie is not None:
                cart = pickle.loads(base64.b64decode(cart_cookie.encode()))

                #更新selected
                for sku_id, data_dict in cart.items():
                    data_dict['selected'] = selected

                # 加密
                cookie_cart = base64.b64encode(pickle.dumps(cart)).decode()
                # 设置购物车的cookie  需要设置有效期否则为临时cookie
                response.set_cookie('cart', cookie_cart, max_age=60 * 60 * 7)
            return response


